﻿using System.ComponentModel;
using LogicStudio.Framework.UI.Comandos;
using System.Runtime.Serialization;
using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel.DataAnnotations;
using System.Linq;

namespace Bede.Framework.UI.Comun
{
    [DataContract]
    public class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo 
    {
        #region fields
        private bool _isDirty;
        #endregion
        #region eventos
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
        #region Comandos
        public RelayCommand RelayCommand;
        #endregion

        #region propiedades
        [DataMember]       
        /// <summary>
        /// Debe true cuando hay cambios en alguna propiedad del view model
        /// y false en caso contrario
        /// </summary>
        public bool IsDirty
        {
            get { return _isDirty; }
            set
            {
                _isDirty = value;
                RaisePropertyChanged("IsDirty");
            }
        }       

        #endregion

        #region metodos publicos
        /// <summary>
        /// Notifica a la interface que hubo cambios en las propiedades del view model
        /// </summary>
        /// <param name="propertyName">Nombre de la propiedad a notificar a la vista</param>
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

        #endregion

        #region INotifyDataErrorInfo Members

       /// <summary> 
        /// Permet d'indiquer qu'une erreur de validation est présente 
        /// </summary> 
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;  
        protected void NotifyErrorsChanged(string propertyName)  
        {  
            if (ErrorsChanged != null)         
                ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));  
        } 
 
 
        private readonly IDictionary<string, IList<string>> _errors = new Dictionary<string, IList<string>>();  
        public IEnumerable GetErrors(string propertyName)  
        {  
            if (_errors.ContainsKey(propertyName))  
            {  
                IList<string> propertyErrors = _errors[propertyName];  
                foreach (string propertyError in propertyErrors)  
                {  
                    yield return propertyError;  
                }  
            }  
            yield break;  
        }  
         
        public bool HasErrors { get { return _errors.Count > 0; } } 
 
 
        protected void ValidateProperty(string propertyName, object value) 
        {  
            ViewModelBase objectToValidate = this; 
            ValidationContext vctx = new ValidationContext(objectToValidate, null, null) 
                                            { 
                                                MemberName = propertyName 
                                            }; 
            var results = new List<ValidationResult>(); 
            bool isValid = Validator.TryValidateProperty(value, vctx, results); 
            
            if (isValid) 
                RemoveErrorsForProperty(propertyName); 
            else  
                AddErrorsForProperty(propertyName, results); 
            NotifyErrorsChanged(propertyName);  
        }  
         
        private void AddErrorsForProperty(string propertyName, IEnumerable<ValidationResult> validationResults)  
        {  
            RemoveErrorsForProperty(propertyName);  
            _errors.Add(propertyName, validationResults.Select(vr => vr.ErrorMessage).ToList());  
        }  
         
        private void RemoveErrorsForProperty(string propertyName)  
        {  
            if (_errors.ContainsKey(propertyName))         
                _errors.Remove(propertyName);  
        } 
 
        public bool ValidateObject()  
        {  
            ViewModelBase objectToValidate = this;  
            _errors.Clear();  
            var results = new List<ValidationResult>();  
            bool isValid = Validator.TryValidateObject(objectToValidate, new ValidationContext(objectToValidate, null, null), results, true); 
            if (!isValid)  
            {  
                IEnumerable<string> propertiesWithMessage = results.SelectMany(vr => vr.MemberNames);  
                foreach (string property in propertiesWithMessage)  
                {  
                    IEnumerable<ValidationResult> messages = results.Where(vr => vr.MemberNames.Contains(property));  
                    AddErrorsForProperty(property, messages);  
                    NotifyErrorsChanged(property);  
                }  
            }  
            return isValid;  
        } 
         
         
  


        #endregion
    }
}
